#ifndef __M_VHOST_H__
#define __M_VHOST_H__

#include "mq_binding.hpp"
#include "mq_exchange.hpp"
#include "mq_message.hpp"
#include "mq_queue.hpp"

namespace wsmq
{
    class VirtualHost
    {
    public:
        using ptr = std::shared_ptr<VirtualHost>;
        VirtualHost(const std::string& hname, 
            const std::string &basedir, const std::string &dbfile):
            _hostname(hname),
            _emp(std::make_shared<ExchangeManager>(dbfile)), 
            _mqmp(std::make_shared<MsgQueueManager>(dbfile)), 
            _bmp(std::make_shared<BindingManager>(dbfile)), 
            _mmp(std::make_shared<MessageManager>(basedir))
        {
            // 消息管理模块提供的恢复数据操作是以队列为单元的
            // 获取所有队列信息，通过队列名称恢复历史队列消息
            MsgQueueMap qmap = _mqmp->allQueues();
            for(auto& q : qmap)
            {
                _mmp->initQueueMessage(q.first);
            }
        }

        bool existExchange(const std::string &name)
        {
            return _emp->exists(name);
        }
        bool declareExchange(const std::string &name, 
            ExchangeType type, bool durable, bool auto_delete,
            const google::protobuf::Map<std::string, std::string>& args)
        {
            return _emp->declareExchange(name, type, durable, auto_delete, args);
        }
        void deleteExchange(const std::string &name)
        {
            // 删除交换机时，也要删除交换机与队列的绑定
            _bmp->removeExchangeBind(name);
            _emp->deleteExchange(name);
        }

        bool existQueue(const std::string &name)
        {
            return _mqmp->exists(name);
        }
        bool declareQueue(const std::string &name,
            bool durable, bool exclusive, bool auto_delete,
            const google::protobuf::Map<std::string, std::string>& args)
        {
            // 创建队列时，要顺便初始化队列的消息句柄（以队列为单元进行消息存储管理）
            _mmp->initQueueMessage(name);
            return _mqmp->declareQueue(name, durable, exclusive, auto_delete, args);
        }
        void deleteQueue(const std::string& name)
        {
            // 删除队列时，要删除交换机与队列间的绑定、队列的消息
            _mmp->destroyQueueMessage(name);
            _bmp->removeQueueBind(name);
            _mqmp->removeQueue(name);
        }

        bool existBinding(const std::string& ename, const std::string& qname)
        {
            return _bmp->exists(ename, qname);
        }
        MsgQueueBindingMap exchangeBindings(const std::string& ename)
        {
            return _bmp->getExchangeBindings(ename);
        }
        bool bind(const std::string& ename, const std::string& qname, const std::string& key)
        {
            // 队列与交换机的绑定需要两者都存在
            Exchange::ptr ep = _emp->selectExchange(ename);
            if(ep.get() == nullptr) 
            {
                DLOG("进行队列绑定失败，交换机%s不存在！", ename.c_str());
                return false;
            }
            MsgQueue::ptr qp = _mqmp->selectMsgQueue(qname);
            if(qp.get() == nullptr) 
            {
                DLOG("进行队列绑定失败，队列%s不存在！", qname.c_str());
                return false;
            }
            // 并且绑定信息的持久化在两者都要持久化时才有意义
            return _bmp->bind(ename, qname, key, ep->durable && qp->_durable);
        }
        void unBind(const std::string& ename, const std::string& qname)
        {
            _bmp->unbind(ename, qname);
        }
        Exchange::ptr selectExchange(const std::string& ename)
        {
            return _emp->selectExchange(ename);
        }
        bool basicPublish(const std::string& qname, const BasicProperties* bp,
            const std::string& body)
        {
            MsgQueue::ptr mqp = _mqmp->selectMsgQueue(qname);
            if(mqp.get() == nullptr)
            {
                DLOG("发布消息失败，队列 %s 不存在", qname.c_str());
                return false;
            }
            return _mmp->insert(qname, bp, body, mqp->_durable);
        }
        MessagePtr basicConsume(const std::string& qname)
        {
            bool ret = _mqmp->exists(qname);
            if(ret == false) return nullptr;
            return _mmp->front(qname);
        }
        void basicAck(const std::string& qname, const std::string& msg_id)
        {
            _mmp->ack(qname, msg_id);
        }
        MsgQueueMap allQueues()
        {
            return _mqmp->allQueues();
        }
        void clear()
        {
            _emp->clear();
            _mqmp->clear();
            _bmp->clear();
            _mmp->clear();
        }
    private:
        std::string _hostname;
        ExchangeManager::ptr _emp;
        MsgQueueManager::ptr _mqmp;
        BindingManager::ptr _bmp;
        MessageManager::ptr _mmp;
    };
}

#endif